package com.bea.ftd.mapping.controller;

import com.bea.ftd.common.dao.ApiDefineRepo;
import com.bea.ftd.common.entity.MsgInConf;
import com.bea.ftd.common.entity.SignInfo;
import com.bea.ftd.common.model.*;
import com.bea.ftd.mapping.feign.EncryptFeign;
import com.bea.ftd.mapping.service.TransMsgService;
import com.bea.ftd.common.utils.XmlUtils;
import com.google.gson.Gson;
import com.sun.org.apache.xerces.internal.xs.datatypes.ObjectList;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

@RestController
public class MessageController {
    private Logger LOGGER = LoggerFactory.getLogger(MessageController.class);

    @Autowired
    TransMsgService transMsgService;

    @Autowired
    ApiDefineRepo apiDefineRepo;

    @Resource
    EncryptFeign encryptFeign;

    @RequestMapping("/hello")
    public String hello(){
        return "hello MappingApplication";
    }

    @RequestMapping("/checkMsgInData")
    public MappingResponse checkMsgInData(@RequestBody MappingRequest data){
        Map<String, Object> result = null;
        MappingResponse res = null;
        try {
            LOGGER.info("根据apiId查询输入报文字段列表......[{}]",data.getApiId());
            List<MsgInConf> msgInConfs = this.transMsgService.findAllMsgInConf(data.getApiId());
            LOGGER.info("报文列表结果返回......[{}],商户代码......[{}]",msgInConfs,data.getPartnerCode());
            SignInfo encryptType = transMsgService.encryptType(data.getPartnerCode());
            LOGGER.info("根据商户代码查询报文加解密算法.....[{}]",encryptType);
            if (msgInConfs.size()!=0&&encryptType!=null){
                if(data.getMsgInType().equalsIgnoreCase("JSON")){
                    Gson gson = new Gson();
                    result = gson.fromJson(data.getData(), Map.class);
                    res = checkMap(result,msgInConfs,encryptType,data);
                }else if(data.getMsgInType().equalsIgnoreCase("XML")){
                    result = XmlUtils.Xml2Map(data.getData());
                    res = checkMap(result,msgInConfs,encryptType,data);
                }
            }else if(msgInConfs.size()==0){
                return new MappingResponse(9,"没有指定报文转换，透传",null);
            }else{
                return new MappingResponse(1,"没有指定加解密类型",null);
            }
        }catch (Exception e){
            e.printStackTrace();
            return new MappingResponse(1,e.toString(),null);
        }
        return res;
    }

    @RequestMapping("/transMsg")
    public MsgOutResponse transMsg(@RequestBody MsgInRequest request)  {
        MsgOutResponse msgOutResponse =null;
        try{
            LOGGER.info("报文转换开始......报文内容[{}]，报文输出类型[{}],apiId[{}]",request.getData(),request.getMsgOutType(),request.getApiId());
            String dataOut = this.transMsgService.mapOutToData(request.getData(),request.getMsgOutType(),request.getApiId());
            if (StringUtils.isNotBlank(dataOut)){
                 msgOutResponse = new MsgOutResponse(0,"输出报文转换成功",dataOut);
            }else {
                msgOutResponse = new MsgOutResponse(1,"转换报文失败，数据为空",dataOut);
            }
            return msgOutResponse;
        }catch (IOException e){
            e.printStackTrace();
            return new MsgOutResponse(1,e.toString(),null);
        }
    }

    private MappingResponse checkMap(Map<String, Object> result,List<MsgInConf> msgInConfs,SignInfo encryptType,MappingRequest data){
        List<List<String>> LinkNodes = getLinkNodes(msgInConfs);//输入报文分解数据结构
        int signParamIndex = 0;
        for(int j=0;j<msgInConfs.size();j++){
            if(msgInConfs.get(j).getEncryptStrategy()==5){
                signParamIndex = j;
            }
        }
        int i=0;
        for(List<String> oneNode:LinkNodes){
            Object value = result;
            for(String oneStringNode:oneNode){
                value = ((Map<String, Object>)value).get(oneStringNode);
                if(value.equals(null)){
                    return new MappingResponse(1,"没有这个字段"+oneNode.get(oneNode.size()-1),null);
                }
            }
            if(!value.getClass().getName().equals(msgInConfs.get(i).getParamType())){
                return new MappingResponse(1,oneNode.get(oneNode.size()-1)+"字段类型错误",null);
            }
            if(value.getClass().getName().equals("java.lang.String")){
                if(((String)value).length()> msgInConfs.get(i).getParamLength()){
                    return new MappingResponse(1,oneNode.get(oneNode.size()-1)+"字段长度错误",null);
                }
                EncryptRequest request = new EncryptRequest();
                switch (msgInConfs.get(i).getEncryptStrategy().intValue()){
                    case 1:{
                        request.setData(value.toString());
                        request.setPartnerCode(data.getPartnerCode());
                        request.setSignType(encryptType.getSignType());
                        request.setEncryptStrategy(1);
                        EncryptResponse response = encryptFeign.gatewayForward(request);
                        if (response.getErrorCode()!=0){
                            return new MappingResponse(1, "加密失败:"+response.getErrorMsg(),null);
                        }
                        break;
                    }
                    case 2:{
                        request.setData(value.toString());
                        request.setPartnerCode(data.getPartnerCode());
                        request.setSignType(encryptType.getSignType());
                        request.setEncryptStrategy(2);
                        EncryptResponse response = encryptFeign.gatewayForward(request);
                        if (response.getErrorCode()!=0){
                            return new MappingResponse(1, "签名失败:"+response.getErrorMsg(),null);
                        }
                        break;}
                    case 3:{
                        request.setData(value.toString());
                        request.setPartnerCode(data.getPartnerCode());
                        request.setSignType(encryptType.getSignType());
                        request.setEncryptStrategy(3);
                        EncryptResponse response = encryptFeign.gatewayForward(request);
                        if (response.getErrorCode()!=0){
                            return new MappingResponse(1, "解密失败:"+response.getErrorMsg(),null);
                        }
                        break;}
                    case 4:{
                        request.setData(value.toString());
                        request.setPartnerCode(data.getPartnerCode());
                        List<String> signList = LinkNodes.get(signParamIndex);
                        Object signValue = result;
                        for(String oneSignList :signList){
                            signValue = ((Map) signValue).get(oneSignList);
                        }
                        request.setSign(signValue.toString());
                        request.setSignType(encryptType.getSignType());
                        request.setEncryptStrategy(4);
                        EncryptResponse response = encryptFeign.gatewayForward(request);
                        if (response.getErrorCode()!=0){
                            return new MappingResponse(1, "验签失败:"+response.getErrorMsg(),null);
                        }
                        break;}
                        default:{
                            break;
                        }
                }
            }
            i++;
        }
        return new MappingResponse(0, "success",result);
    }

    private List<List<String>> getLinkNodes(List<MsgInConf> msgInConfs){
        LOGGER.info("报文字段数据列表分解开始......[{}]",msgInConfs);
        List<List<String>> linkNodes =null;
        for(MsgInConf msgInConf:msgInConfs){
            if(msgInConf.getParentNode().equals("")){
                linkNodes = new ArrayList<>();
                List<String> root = new ArrayList<>();
                root.add(msgInConf.getParamName());
                linkNodes.add(root);
                break;
            }
        }
        if(linkNodes != null ){
            for(MsgInConf msgIn:msgInConfs){
                List<String >otherLinkNode = null;
                for(List<String> oneLindNodes:linkNodes){
                    if(oneLindNodes.get(oneLindNodes.size()-1).equals(msgIn.getParentNode())){
                        otherLinkNode = (ArrayList<String>)((ArrayList<String>) oneLindNodes).clone();
                        otherLinkNode.add(msgIn.getParamName());
                        continue;
                    }
                }
                if(otherLinkNode!=null){
                    linkNodes.add(otherLinkNode);
                }
            }
        }
        return linkNodes;
    }
}

